package com.gopay.bis.manager.bank.ebank;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import com.gopay.bis.common.util.BankLogUtils;
import com.gopay.bis.common.util.TransUtil;
import com.gopay.bis.common.util.TransUtils;
import com.gopay.bis.dao.payconfig.BisBankExtConfigDAO;
import com.gopay.common.Result;
import com.gopay.common.domain.bank.BaseMessage;
import com.gopay.common.domain.bank.cuccpay.ebank.CuccPayMessage;
import com.gopay.common.domain.bis.BaseBisBankExtConfig;
import com.gopay.common.exception.GopayException;
import com.gopay.remote.bank.BankManagerRemoteService;
import com.gopay.remote.bank.businesses.BankService;

/**
 * 联通沃对象封装
 * 
 * CuccPayManager.java
 * 
 * @author WangHongFei
 */
public class CuccPayManager implements BankManagerRemoteService {
	
    @Resource(name = "cuccPayConfig")
    private Map<String, String> cuccPayConfig;
    
    @Resource(name = "cuccPayBankServiceClient")
    private BankService cuccPayBankServiceClient;

	@Resource(name="bisBankExtConfigDAO")
	private BisBankExtConfigDAO bisBankExtConfigDAO;
	
    /**
     * 签名
     * 
     * @param CuccPayMessage
     * @return CuccPayMessage
     */
    public Object sign(BaseMessage message) throws GopayException {
		// 获取银行接口通道配置信息
		BaseBisBankExtConfig bankConfig = bisBankExtConfigDAO.findExtConfigByBankCodeAndBankBusProd(message.getBankBusProd(), message.getBank());
		message.setBankOrderId("CU" + TransUtil.processOrderIdTo14Digit(message.getOrderId()));
		//设置联通沃接口银行码
		message.setSpecial2(bankConfig.getIntrfaceBankCode());
    	CuccPayMessage cuccpayMessage = (CuccPayMessage) message;
    	cuccpayMessage.setBankUrl(cuccpayMessage.getPayUrl());
    	cuccpayMessage.setInterfaceVersion(cuccPayConfig.get("CUCCPAY.INTERFACEVERSION"));
    	cuccpayMessage.setTranType(cuccPayConfig.get("CUCCPAY.TRANTYPE"));
    	cuccpayMessage.setBankCode(cuccpayMessage.getSpecial2());
    	cuccpayMessage.setMerNo(cuccpayMessage.getMerID());
    	cuccpayMessage.setGoodsName(cuccPayConfig.get("CUCCPAY.GOODSNAME"));
        // 商户订单日期为八位
    	cuccpayMessage.setOrderDate(cuccpayMessage.getOrderDate().substring(0, 8));
    	cuccpayMessage.setOrderNo(cuccpayMessage.getBankOrderId());
        // 订单金额，单位：分，金额为大于0的正整数
    	cuccpayMessage.setAmt(TransUtils.amountConvert2Fen(cuccpayMessage.getAmount().toString()));
    	cuccpayMessage.setCharSet(cuccPayConfig.get("CUCCPAY.CHARSET"));
    	cuccpayMessage.setTradeMode(cuccPayConfig.get("CUCCPAY.TRADEMODE"));
    	cuccpayMessage.setExpireTime(cuccPayConfig.get("CUCCPAY.EXPIRETIME"));
    	cuccpayMessage.setReqTime(cuccpayMessage.getOrderDate());
        // 用户ip，如果商户开通防钓鱼功能，此字段必填
    	cuccpayMessage.setReqIp(cuccpayMessage.getSpecial());
    	cuccpayMessage.setRespMode(cuccPayConfig.get("CUCCPAY.RESPMODE"));
    	cuccpayMessage.setCallbackUrl(cuccpayMessage.getPayNotifyUrl());
    	cuccpayMessage.setServerCallUrl(cuccpayMessage.getPayRuturnUrl());
    	cuccpayMessage.setSignType(cuccPayConfig.get("CUCCPAY.SIGNTYPE"));
        // 构建签名所需明文
    	cuccpayMessage.setPlainMessage(buildSignMessage(cuccpayMessage));
        // 发送签名
        BankLogUtils.printB2CManagerSignSendLog(cuccpayMessage);
        String signStr = (String) cuccPayBankServiceClient.sign(cuccpayMessage);
        cuccpayMessage.setSignMsg(signStr);
        BankLogUtils.printB2CManagerSignReturnLog(cuccpayMessage);
        return cuccpayMessage;
    }

    /**
     * 验签
     * 
     * @param CuccPayMessage
     * @return CuccPayMessage
     */
    public Object verify(BaseMessage message) throws GopayException {
    	CuccPayMessage cuccpayMessage = (CuccPayMessage) message;
    	String plainStr = buildVerifyPlain(cuccpayMessage);
    	cuccpayMessage.setPlainMessage(plainStr);
        BankLogUtils.printB2CManagerVerifySendLog(cuccpayMessage);
        boolean flag = (Boolean) cuccPayBankServiceClient.verify(cuccpayMessage);
        BankLogUtils.printB2CManagerVerifyReturnLog(cuccpayMessage, flag);
        return flag;
    }

    /**
     * 查询
     * 
     * @param CuccPayMessage
     * @return CuccPayMessage
     */
    public Object query(Object message) throws GopayException {
    	CuccPayMessage cuccpayMessage = (CuccPayMessage) message;
    	cuccpayMessage.setOrderNo(cuccpayMessage.getBankOrderId());
    	cuccpayMessage.setMerNo(cuccpayMessage.getMerID());
    	cuccpayMessage.setCharSet(cuccPayConfig.get("CUCCPAY.CHARSET"));
    	cuccpayMessage.setSignType(cuccPayConfig.get("CUCCPAY.SIGNTYPE"));
    	cuccpayMessage.setPlainMessage(buildQueryMessage(cuccpayMessage));
        BankLogUtils.printB2CManagerQuerySendLog(cuccpayMessage, "");
        cuccpayMessage = (CuccPayMessage) cuccPayBankServiceClient.query(cuccpayMessage);
        BankLogUtils.printB2CManagerQueryReturnLog(cuccpayMessage);
        return cuccpayMessage;
    }

    /**
     * 组装签名明文
     * 
     * @param CuccPayMessage
     * @return CuccPayMessage
     */
    private String buildSignMessage(CuccPayMessage message) {
        StringBuffer sb = new StringBuffer("");
        // 从a 到z 的顺序排序
        sb.append("amount=").append(message.getAmt());
        sb.append("|bankCode=").append(message.getBankCode());
        sb.append("|callbackUrl=").append(message.getCallbackUrl());
        sb.append("|charSet=").append(message.getCharSet());
        sb.append("|expireTime=").append(message.getExpireTime());
        sb.append("|goodsName=").append(message.getGoodsName());
        sb.append("|interfaceVersion=").append(message.getInterfaceVersion());
        sb.append("|merNo=").append(message.getMerNo());
        sb.append("|orderDate=").append(message.getOrderDate());
        sb.append("|orderNo=").append(message.getOrderNo());
        sb.append("|reqIp=").append(message.getReqIp());
        sb.append("|reqTime=").append(message.getReqTime());
        sb.append("|respMode=").append(message.getRespMode());
        sb.append("|serverCallUrl=").append(message.getServerCallUrl());
        sb.append("|signType=").append(message.getSignType());
        sb.append("|tradeMode=").append(message.getTradeMode());
        sb.append("|tranType=").append(message.getTranType());
        // 商户签名密钥
        sb.append("|key=").append(message.getPrivateKeyPath());
        return sb.toString();
    }

    /**
     * 组装验签所需签名明文
     * 
     * @param CuccPayMessage
     * @return String
     */
    private String buildVerifyPlain(CuccPayMessage message) {
        Map<String, String> resParams = new HashMap<String, String>();
        // 将带签名字符串转换为Map格式
        resParams = splicingData(message.getPlainMessage(), resParams);
        String key = message.getPrivateKeyPath();
        // 调用签名工具类组装签名明文
        String plainMsg = getMd5SignMsg(resParams, key);
        return plainMsg;
    }

    /**
     * 组装订单查询签名明文
     * 
     * @param CuccPayMessage
     * @return String
     */
    private String buildQueryMessage(CuccPayMessage message) {
        StringBuffer sb = new StringBuffer("");
        // 从a 到z 的顺序排序
        sb.append("charSet=").append(message.getCharSet());
        sb.append("|merNo=").append(message.getMerNo());
        sb.append("|orderDate=").append(message.getOrderDate());
        sb.append("|orderNo=").append(message.getOrderNo());
        sb.append("|signType=").append(message.getSignType());
        // 商户签名密钥
        sb.append("|key=").append(message.getPrivateKeyPath());
        return sb.toString();
    }

    /**
     * 将签名字符串转换成Map
     * 
     * @param str
     *            签名字符串
     * @param params
     *            签名Map
     * @param split
     *            分隔符“=”
     * @return Map
     */
    private Map<String, String> splicingData(String str, Map<String, String> params) {
        String split = "\\=";
        String[] data = str.split("\\|");
        for (int i = 0; i < data.length; i++) {
            String methods = data[i];
            String[] method = methods.split(split);
            String key = method[0];
            String value = null;
            if (method.length >= 2) {
                value = "".equals(method[1]) || "null".equals(method[1]) ? null : method[1];
            } else {
                value = null;
            }
            params.put(key, value);
        }
        return params;
    }

    /**
     * 生成MD5方式签名的签名结果
     * 
     * @param sArray
     *            要签名的数组
     * @param key
     *            签名密码
     * @return 签名结果字符串
     */
    private String getMd5SignMsg(Map<String, String> params, String key) {
        params = doFilterParam(params);
        String signSource = createLinkString(params);
        if (key != null && key.length() > 0) {// 证书签名时签名密码为空
            signSource = signSource + "|key=" + key;
        }
        return signSource;
    }

    /**
     * 处理数组中的null值和除去非签名参数
     * 
     * @param params
     *            签名参数组
     * @return 去掉空值与签名参数后的新签名参数组
     */
    private Map<String, String> doFilterParam(Map<String, String> params) {
        List<String> keys = new ArrayList<String>(params.keySet());
        Map<String, String> newParam = new HashMap<String, String>();

        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);

            if ("hmac".equalsIgnoreCase(key) || "signMsg".equalsIgnoreCase(key) || "cert".equalsIgnoreCase(key)) {
                continue;
            }
            if (value == null || value.length() == 0) {
                continue;
            }
            newParam.put(key, value);
        }

        return newParam;
    }

    /**
     * 把数组所有元素排序，并按照“参数=参数值”的模式用“|”字符拼接成字符串
     * 
     * @param params
     *            需要排序并参与字符拼接的参数组
     * @return 拼接后字符串
     */
    private String createLinkString(Map<String, String> params) {
        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);

        StringBuffer prestr = new StringBuffer("");

        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);

            if (i == keys.size() - 1) {// 拼接时，不包括最后一个|字符
                prestr.append(key).append("=").append(value);
            } else {
                prestr.append(key).append("=").append(value).append("|");
            }
        }
        return prestr.toString();
    }

	@Override
	public Object dayend(BaseMessage base) throws GopayException, Exception {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object refund(BaseMessage base) throws GopayException {
		// TODO Auto-generated method stub
		return null;
	}
}
